// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: listener code decoupling
// feature: add SetTrustRemoteEndpoint API to dispatcherReader and add locator to dispatcherWriter
// feature: modify parameter of dispatcher api Add guid and topicname for dsf
// feature: provide query interfaces
// feature: develop dispatcher
// feature: content filter topic
// feature: discovery support client and server
// feature: support message brief record
// feature: dds support get remote participant vbs version and rm some print
// ------------------------------------------------------------------

#ifndef INCLUDE_EDDS_RTPS_PARTICIPANT_RTPSPARTICIPANT_H_
#define INCLUDE_EDDS_RTPS_PARTICIPANT_RTPSPARTICIPANT_H_

#include <ertps/ertps_dll.h>
#include <edds/rtps/common/Guid.h>
#include <edds/rtps/attributes/RTPSParticipantAttributes.h>
#include <ertps/qos/ReaderQos.h>
#include <ertps/qos/WriterQos.h>

#include <cstdlib>
#include <memory>

#include <xmlparser/attributes/XMLTopicAttributes.h>
#include <history/SubstrateParticipant.h>
#include <history/SubstrateWriter.h>
#include <history/SubstrateReader.h>

#include <discovery/database/DiscoveryEndpointInfo.hpp>
#include <discovery/database/DiscoveryParticipantInfo.hpp>
#include <edds/rtps/resources/ResourceEvent.h>
#include <deps/attributes/BaseReaderAttributes.h>
#include <deps/attributes/BaseWriterAttributes.h>

namespace vbs {
namespace common {
class ParticipantListener;
}
}  // namespace vbs
namespace evbs {

namespace edds {
namespace dds {

namespace builtin {

class LookupManager;

}  // namespace builtin
}  // namespace dds
}  // namespace edds

namespace ertps {

using vbsutil::xmlparser::TopicAttributes;
using namespace evbs::ertps::rtps::ddb;
namespace rtps {

class RTPSParticipantImpl;
class RTPSWriter;
class RTPSReader;
class WriterProxyData;
class ReaderProxyData;
class WriterAttributes;
class ReaderAttributes;
class WLP;

/**
 * @brief Class RTPSParticipant, contains the public API for a RTPSParticipant.
 * @ingroup RTPS_MODULE
 */
class RTPS_DllAPI RTPSParticipant : public vbs::dispatcher::SubstrateParticipant {
    friend class RTPSParticipantImpl;
    friend class RTPSDomain;

 private:
    /**
     * Constructor. Requires a pointer to the implementation.
     * @param pimpl Implementation.
     */
    RTPSParticipant(RTPSParticipantImpl* pimpl);

    virtual ~RTPSParticipant();

 public:
    vbs::dispatcher::SubstrateWriter* create_writer(GUID_t guid, vbs::BaseWriterAttributes& watt,
                                                    std::string topic_name, std::string topic_type,
                                                    std::shared_ptr<IPayloadPool>& payload_pool,
                                                    std::shared_ptr<IChangePool>& change_pool, WriterHistory* history,
                                                    WriterListener* listener, Locator_t* local_loc) override;

    vbs::dispatcher::SubstrateReader* create_reader(GUID_t guid, vbs::BaseReaderAttributes& ratt,
                                                    std::string topic_name, std::string topic_type,
                                                    std::shared_ptr<IChangePool>& change_pool, ReaderHistory* history,
                                                    ReaderListener* listener, Locator_t* local_loc) override;
    bool delete_writer(vbs::dispatcher::SubstrateWriter* writer) override;
    bool delete_reader(vbs::dispatcher::SubstrateReader* reader) override;
    bool RegisterTransport(uint32_t type) override;
    bool bTransportRegistered(uint32_t type) override;
    //! Get the GUID_t of the RTPSParticipant.
    const GUID_t& getGuid() const override;
    /**
     * @brief This operation enables the RTPSParticipantImpl
     */
    void enable() override;
    /**
     * @brief Modifies the participant listener
     * @param listener
     */
    void set_listener(vbs::common::ParticipantListener* listener) override;

    ReturnCode_t assert_liveliness(vbs::dispatcher::SubstrateWriter* writer) override;
    ReturnCode_t assert_liveliness() override;

    /**
     * @brief Retrieves the built-in lookup service manager.
     * @return
     */
    edds::dds::builtin::LookupManager* lookup_manager() const;

    //! Force the announcement of the RTPSParticipant state.
    void announceRTPSParticipantState();

    //	//!Method to loose the next change (ONLY FOR TEST). //TODO remove this method because is
    // only for testing 	void loose_next_change();

    //! Stop the RTPSParticipant announcement period. //TODO remove this method because is only for
    //! testing
    void stopRTPSParticipantAnnouncement();

    //! Reset the RTPSParticipant announcement period. //TODO remove this method because is only for
    //! testing
    void resetRTPSParticipantAnnouncement();

    // Start to send announcement message with initial announcement period.
    bool startRTPSParticipantInitialAnnouncement(uint32_t count, ertps::Duration_t period);

    /**
     * Indicate the Participant that you have discovered a new Remote Writer.
     * This method can be used by the user to implements its own Static Endpoint
     * Discovery Protocol
     * @param pguid GUID_t of the discovered Writer.
     * @param userDefinedId ID of the discovered Writer.
     * @return True if correctly added.
     */

    bool newRemoteWriterDiscovered(const GUID_t& pguid, int16_t userDefinedId);
    /**
     * Indicate the Participant that you have discovered a new Remote Reader.
     * This method can be used by the user to implements its own Static Endpoint
     * Discovery Protocol
     * @param pguid GUID_t of the discovered Reader.
     * @param userDefinedId ID of the discovered Reader.
     * @return True if correctly added.
     */
    bool newRemoteReaderDiscovered(const GUID_t& pguid, int16_t userDefinedId);

    /**
     * Get the Participant ID.
     * @return Participant ID.
     */
    uint32_t getRTPSParticipantID() const;

    /**
     * Register a RTPSWriter in the builtin Protocols.
     * @param Writer Pointer to the RTPSWriter.
     * @param topicAtt Topic Attributes where you want to register it.
     * @param wqos WriterQos.
     * @return True if correctly registered.
     */
    bool registerWriter(vbs::dispatcher::SubstrateWriter* Writer, const BaseTopicAttributes& topicAtt,
                        const BaseWriterQos& wqos,
                        const vbsutil::xmlparser::ContentFilterProperty* content_filter = nullptr) override;

    /**
     * Register a RTPSReader in the builtin Protocols.
     * @param Reader          Pointer to the RTPSReader.
     * @param topicAtt        Topic Attributes where you want to register it.
     * @param rqos            ReaderQos.
     * @return True if correctly registered.
     */
    bool registerReader(vbs::dispatcher::SubstrateReader* Reader, const BaseTopicAttributes& topicAtt,
                        const BaseReaderQos& rqos,
                        const vbsutil::xmlparser::ContentFilterProperty* content_filter = nullptr) override;

    /**
     * Update participant attributes.
     * @param patt New participant attributes.
     */
    void update_attributes(const RTPSParticipantAttributes& patt);

    /**
     * Update writer QOS
     * @param Writer to update
     * @param topicAtt Topic Attributes where you want to register it.
     * @param wqos New writer QoS
     * @return true on success
     */
    bool updateWriter(vbs::dispatcher::SubstrateWriter* Writer, const BaseTopicAttributes& topicAtt,
                      const BaseWriterQos& wqos,
                      const vbsutil::xmlparser::ContentFilterProperty* content_filter = nullptr,
                      bool notify = true) override;

    /**
     * Update reader QOS
     * @param Reader          Pointer to the RTPSReader to update
     * @param topicAtt        Topic Attributes where you want to register it.
     * @param rqos            New reader QoS
     * @return true on success
     */
    bool updateReader(vbs::dispatcher::SubstrateReader* Reader, const BaseTopicAttributes& topicAtt,
                      const BaseReaderQos& rqos,
                      const vbsutil::xmlparser::ContentFilterProperty* content_filter = nullptr,
                      bool notify = true) override;

    /**
     * Returns a list with the participant names.
     * @return list of participant names.
     */
    std::vector<std::string> getParticipantNames() const;

    std::string prinfParticipantNames() const;
    /**
     * Get a copy of the actual state of the RTPSParticipantParameters
     * @return RTPSParticipantAttributes copy of the params.
     */
    const RTPSParticipantAttributes& getRTPSParticipantAttributes() const;

    /**
     * Retrieves the maximum message size.
     */
    uint32_t getMaxMessageSize() const;

    /**
     * Retrieves the maximum data size.
     */
    uint32_t getMaxDataSize() const;

    ResourceEvent& get_resource_event() const;

    /**
     * @brief A method to retrieve the built-in writer liveliness protocol
     * @return Writer liveliness protocol
     */
    WLP* wlp() const;

    /**
     * @brief Fills a new entityId if set to unknown, or checks if a entity already exists with that
     * entityId in other case.
     * @param entityId to check of fill. If filled, EntityKind will be "vendor-specific" (0x01)
     * @return True if filled or the entityId is available.
     */
    bool get_new_entity_id(EntityId_t& entityId);

    /**
     * Allows setting a function to check if a type is already known by the top level API
     * participant.
     */
    void set_check_type_function(std::function<bool(const std::string&)>&& check_type);

    /**
     * @brief Retrieves the DomainId.
     */
    uint32_t get_domain_id() const;

    /**
     * @brief Ignore all messages coming from the RTPSParticipant
     *
     * @param [in] participant_guid RTPSParticipant GUID to be ignored
     * @return True if correctly included into the ignore collection. False otherwise.
     */
    bool ignore_participant(const GuidPrefix_t& participant_guid);

    /**
     * @brief Ignore all messages coming from the RTPSWriter
     *
     * @param [in] writer_guid RTPSWriter GUID to be ignored
     * @return True if correctly included into the ignore collection. False otherwise.
     */
    bool ignore_writer(const GUID_t& writer_guid);

    /**
     * @brief Ignore all messages coming from the RTPSReader
     *
     * @param [in] reader_guid RTPSReader GUID to be ignored
     * @return True if correctly included into the ignore collection. False otherwise.
     */
    bool ignore_reader(const GUID_t& reader_guid);

#if HAVE_SECURITY

    /**
     * @brief Checks whether the writer has security attributes enabled
     * @param writer_attributes Attributes of the writer as given to the
     * RTPSParticipantImpl::create_writer
     */

    bool is_security_enabled_for_writer(const WriterAttributes& writer_attributes);

    /**
     * @brief Checks whether the reader has security attributes enabled
     * @param reader_attributes Attributes of the reader as given to the
     * RTPSParticipantImpl::create_reader
     */

    bool is_security_enabled_for_reader(const ReaderAttributes& reader_attributes);

#endif  // if HAVE_SECURITY

    /**
     * @brief get remote evbs version
     *
     * @return evbsVersion
     */
    EvbsVersion_t get_remote_evbsversion();

    const std::vector<RTPSWriter*>& getAllWriters() const;

    const std::vector<RTPSReader*>& getAllReaders() const;

    std::string get_db_info(bool log_record);

    // Get all the participants in DataBase
    bool get_participants_in_db(std::vector<GuidPrefix_t>& prefix_list) const override;

    // Get the participant info by guid_prefix
    bool get_participant_info(const GuidPrefix_t& prefix, DiscoveryParticipantInfo& part_info) const;

    // Get the reader info by guid
    bool get_reader_info(const GUID_t& reader_guid, DiscoveryEndpointInfo& reader_info) const;

    // Get the writer info by guid
    bool get_writer_info(const GUID_t& writer_guid, DiscoveryEndpointInfo& writer_info) const;

    bool get_topic_names(std::vector<std::string>& topic_list) const override;

    bool has_writer(const std::string& topic_name) const override;

    bool has_reader(const std::string& topic_name) const override;

    bool get_writer_of_topic(const std::string& topic_name, std::vector<DiscoveryEndpointInfo>& writer_info_list) const;

    bool get_reader_of_topic(const std::string& topic_name, std::vector<DiscoveryEndpointInfo>& reader_info_list) const;

    bool has_participant(const std::string& participant_name) const override;

    bool get_participant_of_name(const std::string& participant_name, DiscoveryParticipantInfo& part_info) const;

 private:
    //! Pointer to the implementation.
    RTPSParticipantImpl* mp_impl;
};

}  // namespace rtps
}  // namespace ertps
} /* namespace evbs */

#endif  // INCLUDE_EDDS_RTPS_PARTICIPANT_RTPSPARTICIPANT_H_
